import socket
import threading
import time
import logging
from queue import Queue
from request_queue import SerialRequest

logger = logging.getLogger('ClientHandler')

class ClientHandler:
    """TCP客户端处理类"""
    def __init__(self, client_socket, client_id, request_queue, timeout=30):
        self.client_socket = client_socket
        self.client_id = client_id
        self.request_queue = request_queue
        self.timeout = timeout
        self.active = True
        self.last_active = time.time()
        self.send_queue = Queue()
        self.connection_closed = False
        
    def start(self):
        """启动客户端处理线程"""
        # 接收线程
        recv_thread = threading.Thread(target=self._receive_loop)
        recv_thread.daemon = True
        recv_thread.start()
        
        # 发送线程
        send_thread = threading.Thread(target=self._send_loop)
        send_thread.daemon = True
        send_thread.start()
        
        # 心跳检查线程
        heartbeat_thread = threading.Thread(target=self._heartbeat_check)
        heartbeat_thread.daemon = True
        heartbeat_thread.start()
        
        logger.info("{}: 客户端处理已启动".format(
            self.client_id
        ))
        
    def _receive_loop(self):
        """接收数据循环"""
        try:
            while self.active and not self.connection_closed:
                try:
                    data = self.client_socket.recv(1024)
                    if not data:
                        #logger.info(f"客户端 {self.client_id} 主动断开连接")
                        logger.info("{}: 客户端主动断开连接".format(
                            self.client_id
                        ))

                        break
                    else:
                        #logger.info(f"客户端 {self.client_id} 发送: {data}")
                        logger.debug("{}: 客户端发送: {}".format(
                            self.client_id,
                            data
                        ))

                    
                    self.last_active = time.time()
                    
                    # 创建请求并添加到队列
                    request = SerialRequest(
                        self.client_id, 
                        data, 
                        self._response_callback
                    )
                    
                    if not self.request_queue.add_request(request):
                        #logger.warning(f"请求队列已满，拒绝客户端 {self.client_id} 的请求")
                        logger.warning("{}: 请求队列已满，拒绝客户端请求".format(
                            self.client_id
                        ))

                        # 可以在这里发送错误响应给客户端
                
                except socket.timeout:
                    # 检查客户端是否超时
                    if time.time() - self.last_active > self.timeout:
                        #logger.info(f"客户端 {self.client_id} 接收超时")
                        logger.info("{}: 客户端接收超时".format(
                            self.client_id
                        ))

                        break
                    continue
                except ConnectionResetError:
                    #logger.info(f"客户端 {self.client_id} 连接重置")
                    logger.info("{}: 客户端连接重置".format(
                        self.client_id
                    ))

                    break
                except Exception as e:
                    #logger.error(f"从客户端 {self.client_id} 接收错误: {str(e)}")
                    logger.error("{}: 从客户端接收错误: {}".format(
                        self.client_id,
                        str(e)
                    ))

                    break
        finally:
            self.connection_closed = True
            #logger.info(f"客户端 {self.client_id} 接收循环结束")
            logger.info("{}: 客户端接收循环结束".format(
                self.client_id
            ))

    
    def _send_loop(self):
        """发送数据循环"""
        try:
            while self.active and not self.connection_closed:
                try:
                    # 从发送队列获取数据
                    data = self.send_queue.get(timeout=1.0)
                    if data:
                        try:
                            self.client_socket.sendall(data)
                            self.last_active = time.time()
                            logger.debug("向客户端 {} 回复: {}".format(
                                self.client_id,
                                data
                            ))

                        except (ConnectionResetError, BrokenPipeError):
                            #logger.info(f"客户端 {self.client_id} 发送时连接已断开")
                            logger.info("{}: 客户端发送时连接已断开".format(
                                self.client_id
                            ))

                            self.connection_closed = True
                            break
                except Exception:
                    # 主要是队列超时异常，继续循环
                    continue
        except Exception as e:
            #logger.error(f"发送到客户端 {self.client_id} 错误: {str(e)}")
            logger.error("{}: 发送到客户端错误: {}".format(
                self.client_id,
                str(e)
            ))

        finally:
            self.connection_closed = True
            #logger.info(f"客户端 {self.client_id} 发送循环结束")
            logger.info("{}: 客户端发送循环结束".format(
                self.client_id
            ))

    
    def _heartbeat_check(self):
        """心跳检查，定期检测连接状态"""
        try:
            while self.active and not self.connection_closed:
                time.sleep(5)  # 每5秒检查一次
                
                # 检查连接是否超时
                if time.time() - self.last_active > self.timeout:
                    #logger.info(f"客户端 {self.client_id} 心跳超时")
                    logger.info("{}: 客户端心跳超时".format(
                        self.client_id
                    ))

                    self.connection_closed = True
                    break
                    
                # 尝试发送空数据检测连接状态
                try:
                    self.client_socket.send(b'')
                except (ConnectionResetError, BrokenPipeError, OSError):
                    #logger.info(f"客户端 {self.client_id} 心跳检测失败")
                    logger.info("{}: 客户端心跳检测失败".format(
                        self.client_id
                    ))

                    self.connection_closed = True
                    break
        except Exception as e:
            #logger.error(f"客户端 {self.client_id} 心跳检查错误: {str(e)}")
            logger.error("{}: 客户端心跳检查错误: {}".format(
                self.client_id,
                str(e)
            ))

            self.connection_closed = True
    
    def _response_callback(self, response_data):
        """响应回调函数"""
        if self.active and not self.connection_closed:
            self.send_queue.put(response_data)
    
    def close(self):
        """关闭客户端连接"""
        self.active = False
        self.connection_closed = True
        try:
            self.client_socket.close()
        except:
            pass
        #logger.info(f"客户端 {self.client_id} 已关闭")
        logger.info("{}: 客户端已关闭".format(
            self.client_id
        ))

    
    def is_connected(self):
        """检查客户端是否仍连接"""
        return self.active and not self.connection_closed